package com.acwer.drgs.performance.controller;

import com.acwer.common.RpnMsg;
import com.acwer.dao.domain.DrgStd;
import com.acwer.dao.mapper.DrgStdMapper;
import com.acwer.drgs.performance.domain.FieldInfo;
import com.acwer.drgs.performance.es.domain.PerfmDic;
import com.acwer.drgs.performance.es.repo.PerfmDicRepo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.*;
import net.sf.jsqlparser.statement.select.Join;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.join.query.HasParentQueryBuilder;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.annotation.RequestScope;

import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.Wrapper;
import java.util.*;


@RestController
@RequestMapping("conf")
//用于nacos刷新配置
@RequestScope
@Api(value = "各种配置信息",description = "各种配置信息 如：数据字典")
public class ConfController {

    @Autowired
    PerfmDicRepo dicRepo;

    @ApiOperation("获取数据字典列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "docType",value = "文档类型（默认返回父文档，即字典大类）：<font color='red'>'p'</font> 父文档，如：职业代码、性别代码。<br/><font color='red'>'c'</font> 子文档代码，如：11\t国家公务员"),
            @ApiImplicitParam(name = "id",value = "<font color='red'>文档ID。<br/>docType为空时，返回当前ID的数据，其他参数应不填。<br/>docType=c时，应传入父ID，返回子文档列表<br/></font>"),
            @ApiImplicitParam(name = "pageIndex",value = "当前分页"),
            @ApiImplicitParam(name = "pageSize",value = "每页大小"),
            @ApiImplicitParam(name = "s",value = "字段值是否包含某些关键字 字段包括：code，name，mark")
    })
    @ApiResponses({
            @ApiResponse(code=0,message="请求成功"),
            @ApiResponse(code=1,message="请求失败"),
    })
    @GetMapping("dic-ls")
    public RpnMsg<Page<PerfmDic>> findDic(
            @RequestParam(defaultValue = "") String docType,
            @RequestParam(defaultValue = "") String id,
            @RequestParam(defaultValue = "1") Integer pageIndex,
            @RequestParam(defaultValue = "10") Integer pageSize,
            @RequestParam(defaultValue = "") String s

    ){
        NativeSearchQueryBuilder nQuery = new NativeSearchQueryBuilder();
        nQuery.withPageable(PageRequest.of(pageIndex-1,pageSize));

        BoolQueryBuilder must=QueryBuilders.boolQuery();
        //1.查询关键字
        if(!StringUtils.isEmpty(s)){
            BoolQueryBuilder should= QueryBuilders.boolQuery();
            should.should(QueryBuilders.matchPhraseQuery("code",s));
            should.should(QueryBuilders.matchPhraseQuery("name",s));
            must.must(should);
        }
        if(!StringUtils.isEmpty(docType)){
            //如果 docType='c',id不为空，则查询子文档相关列表
            if("c".equals(docType)&&!StringUtils.isEmpty(id)){
                must.must(JoinQueryBuilders.parentId(docType,id));
            }
        }
        //查询指定文档
        if(StringUtils.isEmpty(docType)&&!StringUtils.isEmpty(id)){
            must.must(QueryBuilders.idsQuery().addIds(id));
        }
        //默认返回父文档
        if(StringUtils.isEmpty(docType)&&StringUtils.isEmpty(id)){
            must.must(QueryBuilders.termQuery("join","p"));
        }
        nQuery.withQuery(must);

        Page<PerfmDic> page = dicRepo.search(nQuery.build());

        return RpnMsg.SUCCESS(page);
    }

    @ApiOperation("一次添加或修改添加或修改字典")
    @PostMapping("dic-save")
    public RpnMsg saveDic(@RequestBody PerfmDic dic){
        dicRepo.save(dic);
        return RpnMsg.SUCCESS();
    }

    @ApiOperation("一次添加或修改多个字典")

    @PostMapping("dic-saves")
    public RpnMsg saveDics(@RequestBody List<PerfmDic> ls){
        dicRepo.saveAll(ls);
        return RpnMsg.SUCCESS();
    }

    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;
    @ApiOperation("按文档ID删除字典")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "ids",value = "文档ID List集合。如果删除某个父文档，应该删除它所有的子文档")
    })
    @PostMapping("dic-destory-byids")
    public RpnMsg destroyDicByIds(@RequestBody List<String>ids){

        IdsQueryBuilder idsQueryBuilder = QueryBuilders.idsQuery().addIds(ids.toArray(new String[0]));
        HasParentQueryBuilder p = JoinQueryBuilders.hasParentQuery("p", idsQueryBuilder, false);
        NativeSearchQuery q=new NativeSearchQuery(p);
        //删除字文档
        elasticsearchRestTemplate.delete(q,PerfmDic.class);
        //TODO:改成批量删除
        for (String id : ids) {
            dicRepo.deleteById(id);
        }
        return RpnMsg.SUCCESS();
    }

    @ApiOperation("通过父文档code查找子文档")
    @GetMapping("dic-child-bycode")
    public RpnMsg dicChildByCode(String code){
        HasParentQueryBuilder p = JoinQueryBuilders.hasParentQuery("p", QueryBuilders.termQuery("code.keyword", code), false);
        NativeSearchQuery q=new NativeSearchQuery(p);
        q.setPageable(PageRequest.of(0,10000));
        Page<PerfmDic> search = dicRepo.search(q);
        List<PerfmDic> content = search.getContent();
        return RpnMsg.SUCCESS(content);
    }


    //字段缓存MAP
    private Map<String,List<FieldInfo>> cacheInfo=new Hashtable<String,List<FieldInfo>>();

    @ApiOperation("获取实体的字段在UI上的显示名称")
    @ApiImplicitParam(name = "entity",value = "实体名字")
    @GetMapping("field-info")
    public RpnMsg fieldInfo(
            @RequestParam(defaultValue = "") String entity
    ){

        RpnMsg msg=RpnMsg.SUCCESS();
        //生成字段名MAP
        if(cacheInfo.size()==0){
            setAndcachFieldInfo();
        }

        //如果有带参数，获取部分
        if(!StringUtils.isEmpty(entity)){
            if(cacheInfo.containsKey(entity)){

                msg.setData(new HashMap<String,List<FieldInfo>>(){
                    {
                        put(entity,cacheInfo.get(entity));
                    }
                });
            }
        }else {
            //返回所有
            msg.setData(cacheInfo);
        }


        return  msg;
    }
    private void setAndcachFieldInfo(){
        String BASE_PACKAGE = "com.acwer.drgs.performance.es.domain";
        String RESOURCE_PATTERN = "/**/*.class";
        RpnMsg msg=RpnMsg.SUCCESS();
        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                    ClassUtils.convertClassNameToResourcePath(BASE_PACKAGE) + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            //MetadataReader 的工厂类
            MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                //用于读取类信息
                MetadataReader reader = readerfactory.getMetadataReader(resource);
                //扫描到的class
                String classname = reader.getClassMetadata().getClassName();
                Class<?> clazz = Class.forName(classname);
                //判断是否有指定主解
                ApiModel anno = clazz.getAnnotation(ApiModel.class);

                boolean isExists=anno != null;
                if(!isExists){
                    continue;
                }

                //获取所有字段相关的信息

                List<FieldInfo> fieldInfos=new ArrayList<>();
                for (Field field : clazz.getDeclaredFields()) {
                    ApiModelProperty mp = field.getAnnotation(ApiModelProperty.class);
                    FieldInfo fi=new FieldInfo();
                    fi.setCol(field.getName());
                    fi.setFieldType(field.getType().getName());
                    //UI要显示的名称
                    if(mp!=null){
                        fi.setName(mp.value());
                        if(!StringUtils.isEmpty(mp.notes())){
                            try {
                                JSONObject o = JSON.parseObject(mp.notes(), JSONObject.class);
                                if(o.containsKey("ls")){
                                    fi.setLs(o.getBoolean("ls"));
                                }
                            }catch (Exception e){}
                        }
                    }else {
                        fi.setName(fi.getCol());
                    }
                    //是否主键
                    Id idMp = field.getAnnotation(Id.class);
                    fi.setPrimaryKey(idMp!=null);
                    fieldInfos.add(fi);
                }

                cacheInfo.put(anno.value(),fieldInfos);

            }
        } catch (IOException | ClassNotFoundException e) {
        }
    }

    @Autowired
    DrgStdMapper drgStdMapper;

    @ApiOperation("获取DRG权重")
    @GetMapping("drg-std")
    public RpnMsg<IPage<DrgStd>> drgStd(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "") String s
    ){
        QueryWrapper<DrgStd> wrapper=new QueryWrapper<>();
        s=s.trim();
        if(!StringUtils.isEmpty(s)){
            wrapper.like("MDC专业",s).or().like("MDC中文名称",s);
            wrapper.like("分组编码",s).or().like("分组名称",s)
                    .or().like("组别",s);
        }
        IPage<DrgStd> pg=new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(page,size);
        IPage<DrgStd> stdPage = drgStdMapper.selectPage(pg,wrapper);
        return RpnMsg.SUCCESS(stdPage);
    }
}
